/*global pi */
pi.mod.define('pi.scene.creators', function (pi) {
	"use strict";

	var i, module = {},
		meshID = 0,
		vcalls = [
			["s3d_update_sk_animation", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_FLOAT]],
			["s3d_get_sk_bonenum", pi.vcall.TYPE_INT, [pi.vcall.TYPE_INT]],
			["s3d_get_bone_mats", pi.vcall.TYPE_INT, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT]],
			["s3d_set_bind_to", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_INT]]
		],
		createLines = function (lines) {
			var i, num, startPt, endPt, c, vertices, colors, indexes, indArr, h;
			num = lines.length;

			vertices = pi.lang.createF32Array(6 * num);
			colors = pi.lang.createU8Array(8 * num);
			indexes = pi.lang.createI32Array(2 * num);

			for (i = 0; i < num; i++) {
				startPt = lines[i].start;
				endPt = lines[i].end;
				c = lines[i].color || {
					r: 255,
					g: 255,
					b: 255,
					a: 255
				};

				vertices[i * 6] = startPt.x;
				vertices[i * 6 + 1] = startPt.y;
				vertices[i * 6 + 2] = startPt.z;
				vertices[i * 6 + 3] = endPt.x;
				vertices[i * 6 + 4] = endPt.y;
				vertices[i * 6 + 5] = endPt.z;
				colors[i * 8] = colors[i * 8 + 4] = c.r;
				colors[i * 8 + 1] = colors[i * 8 + 5] = c.g;
				colors[i * 8 + 2] = colors[i * 8 + 6] = c.b;
				colors[i * 8 + 3] = colors[i * 8 + 7] = c.a;
				indexes[i * 2] = i * 2;
				indexes[i * 2 + 1] = i * 2 + 1;
			}

			h = pi.render.t3d.createMesh(pi.render.t3d.GEO_TYPE_LINE_LIST, pi.render.t3d.INDEX_TYPE_32BIT, 2 * num, vertices, colors, 2 * num, indexes);

			return pi.res.create(h, undefined, function (handle) {
				pi.render.t3d.destroyMesh(handle);
			});
		},
		createSector = function (radius, radians, color, num) {
			var i, tempRadians, vNum, iNum, vertex, index, h, cNum, colors;
			num = num || 5;
			color = color || {
				r: 255,
				g: 255,
				b: 255,
				a: 255
			};
			vNum = (num + 2) * 3;
			iNum = num * 3;
			cNum = (num + 2) * 4;
			vertex = pi.lang.createF32Array(vNum); //顶点数组
			index = pi.lang.createI32Array(iNum); //索引数组
			colors = pi.lang.createU8Array(cNum);
			vertex[0] = 0.0;
			vertex[1] = 0.0;
			vertex[2] = 0.0;
			colors[0] = color.r;
			colors[1] = color.g;
			colors[2] = color.b;
			colors[3] = color.a || 1;

			for (i = 0; i <= num; i++) {
				tempRadians = (Math.PI / 2) - radians + (radians * 2 / num) * i;
				vertex[(i + 1) * 3] = radius * Math.cos(tempRadians);
				vertex[(i + 1) * 3 + 1] = 0.0;
				vertex[(i + 1) * 3 + 2] = radius * Math.sin(tempRadians);
				colors[(i + 1) * 4] = color.r;
				colors[(i + 1) * 4 + 1] = color.g;
				colors[(i + 1) * 4 + 2] = color.b;
				colors[(i + 1) * 4 + 3] = color.a || 1;
			}

			i = 0;
			while (i < num) {
				index[i * 3] = i + 2;
				index[i * 3 + 1] = i + 1;
				index[i * 3 + 2] = 0;
				i++;
			}

			h = pi.render.t3d.createMesh(pi.render.t3d.GEO_TYPE_TRIANGLE_LIST, pi.render.t3d.INDEX_TYPE_32BIT, num + 2, vertex, colors, iNum, index);
			return pi.res.create(h, undefined, function (handle) {
				pi.render.t3d.destroyMesh(handle);
			});
		},
		createCone = function (radius, height, color, num) {
			var radians, vNum, iNum, cNum, vertex, index, colors, tempRadians, i, j, h;
			vNum = (num + 2) * 3;
			iNum = num * 6;
			cNum = (num + 2) * 4;
			vertex = pi.lang.createF32Array(vNum); //顶点数组
			index = pi.lang.createI32Array(iNum); //索引数组
			colors = pi.lang.createU8Array(cNum);
			colors[0] = color.r;
			colors[1] = color.g;
			colors[2] = color.b;
			colors[3] = color.a || 1;
			colors[4] = color.r;
			colors[5] = color.g;
			colors[6] = color.b;
			colors[7] = color.a || 1;

			radians = Math.PI * 2 / num;
			vertex[0] = 0.0;
			vertex[1] = 0.0;
			vertex[2] = 0.0;
			vertex[3] = 0.0;
			vertex[4] = height;
			vertex[5] = 0.0;

			for (i = 0; i < num; i++) {
				tempRadians = i * radians;
				vertex[(i + 2) * 3] = radius * Math.cos(tempRadians);
				vertex[(i + 2) * 3 + 1] = 0.0;
				vertex[(i + 2) * 3 + 2] = radius * Math.sin(tempRadians);
				colors[(i + 2) * 4] = color.r;
				colors[(i + 2) * 4 + 1] = color.g;
				colors[(i + 2) * 4 + 2] = color.b;
				colors[(i + 2) * 4 + 3] = color.a || 1;
			}
			i = 0;
			j = 0;
			while (i < num) {
				index[i * 3] = 1;
				index[i * 3 + 1] = i + 3;
				index[i * 3 + 2] = i + 2;
				if (i === num - 1) {
					index[i * 3 + 1] = 2;
				}
				i++;
			}
			while (j < num) {
				index[i * 3] = i + 3;
				index[i * 3 + 1] = i + 2;
				index[i * 3 + 2] = 0;
				if (j === num - 1) {
					index[i * 3] = 2;
				}
				i++;
				j++;
			}

			h = pi.render.t3d.createMesh(pi.render.t3d.GEO_TYPE_TRIANGLE_LIST, pi.render.t3d.INDEX_TYPE_32BIT, num + 2, vertex, colors, iNum, index);
			return pi.res.create(h, undefined, function (handle) {
				pi.render.t3d.destroyMesh(handle);
			});
		},
		createCylinder = function (radius, height, color, num) {
			var radians, vNum, iNum, cNum, vertex, index, colors, tempRadians, i, j, h;
			vNum = (2 * num + 2) * 3;
			iNum = num * 6 + num * 6;
			cNum = (2 * num + 2) * 4;
			radians = Math.PI * 2 / num;
			vertex = pi.lang.createF32Array(vNum); //顶点数组
			index = pi.lang.createI32Array(iNum); //索引数组
			colors = pi.lang.createU8Array(cNum);
			colors[0] = color.r;
			colors[1] = color.g;
			colors[2] = color.b;
			colors[3] = color.a || 1;
			colors[4] = color.r;
			colors[5] = color.g;
			colors[6] = color.b;
			colors[7] = color.a || 1;

			vertex[0] = 0.0;
			vertex[1] = -height;
			vertex[2] = 0.0;
			vertex[3] = 0.0;
			vertex[4] = height;
			vertex[5] = 0.0;

			for (i = 0; i < num; i++) {
				tempRadians = i * radians;
				vertex[(i + 2) * 3] = radius * Math.cos(tempRadians);
				vertex[(i + 2) * 3 + 1] = -height;
				vertex[(i + 2) * 3 + 2] = radius * Math.sin(tempRadians);
				colors[(i + 2) * 4] = color.r;
				colors[(i + 2) * 4 + 1] = color.g;
				colors[(i + 2) * 4 + 2] = color.b;
				colors[(i + 2) * 4 + 3] = color.a || 1;
			}
			for (j = 0; j < num; j++) {
				tempRadians = i * radians;
				vertex[(i + 2) * 3] = radius * Math.cos(tempRadians);
				vertex[(i + 2) * 3 + 1] = height;
				vertex[(i + 2) * 3 + 2] = radius * Math.sin(tempRadians);
				colors[(i + 2) * 4] = color.r;
				colors[(i + 2) * 4 + 1] = color.g;
				colors[(i + 2) * 4 + 2] = color.b;
				colors[(i + 2) * 4 + 3] = color.a || 1;
				i++;
			}
			//计算索引数组
			i = 0;
			j = 0;
			while (i < num) {
				index[i * 3] = i + 3;
				index[i * 3 + 1] = i + 2;
				index[i * 3 + 2] = 0;
				if (i === num - 1) {
					index[i * 3] = 2;
				}
				i++;
			}
			while (j < num) {
				index[i * 3] = j + num + 3;
				index[i * 3 + 1] = j + num + 2;
				index[i * 3 + 2] = 1;
				if (j === num - 1) {
					index[i * 3] = num + 2;
				}
				i++;
				j++;
			}

			for (j = 0; j < num; j++) {
				index[i * 3] = j + 2;
				index[i * 3 + 1] = j + 2 + num;
				index[i * 3 + 2] = j + 3 + num;
				if (j === num - 1) {
					index[i * 3 + 2] = num + 2;
				}
				i++;
				index[i * 3] = j + 2;
				index[i * 3 + 1] = j + 3 + num;
				index[i * 3 + 2] = j + 3;
				if (j === num - 1) {
					index[i * 3 + 1] = num + 2;
					index[i * 3 + 2] = 2;
				}
				i++;
			}

			h = pi.render.t3d.createMesh(pi.render.t3d.GEO_TYPE_TRIANGLE_LIST, pi.render.t3d.INDEX_TYPE_32BIT, 2 * num + 2, vertex, colors, iNum, index);
			return pi.res.create(h, undefined, function (handle) {
				pi.render.t3d.destroyMesh(handle);
			});

		},
		createCube = function (onlyFrame, color) {
			var i, j, x, y, z, h, vertices, colors, indexes, indArr, min = {},
				max = {};

			color = color || {
				r: 255,
				g: 255,
				b: 255,
				a: 255
			};
			min.x = min.y = min.z = -0.5;
			max.x = max.y = max.z = 0.5;

			// 计算 8 个顶点坐标
			vertices = pi.lang.createF32Array(24);
			colors = pi.lang.createU8Array(32);
			for (x = 0; x <= 1; x++) {
				for (y = 0; y <= 1; y++) {
					for (z = 0; z <= 1; z++) {
						i = x * 4 + y * 2 + z;
						vertices[i * 3] = x === 0 ? min.x : max.x;
						vertices[i * 3 + 1] = y === 0 ? min.y : max.y;
						vertices[i * 3 + 2] = z === 0 ? min.z : max.z;
						colors[i * 4] = color.r;
						colors[i * 4 + 1] = color.g;
						colors[i * 4 + 2] = color.b;
						colors[i * 4 + 3] = color.a || 1;
					}
				}
			}

			if (onlyFrame) {
				// 计算 12 边框线的顶点索引
				indexes = pi.lang.createI32Array(24);
				indArr = [0, 1, 1, 3, 3, 2, 2, 0, 4, 5, 5, 7, 7, 6, 6, 4, 2, 6, 3, 7, 0, 4, 1, 5];
				for (i = 0; i < indArr.length; i++) {
					indexes[i] = indArr[i];
				}
				h = pi.render.t3d.createMesh(pi.render.t3d.GEO_TYPE_LINE_LIST,
					pi.render.t3d.INDEX_TYPE_32BIT,
					8, vertices, colors, 24, indexes);
			} else {
				// 计算 12 个面的顶点索引
				indexes = pi.lang.createI32Array(36);
				indArr = [0, 1, 3, 0, 3, 2, 7, 5, 4, 7, 4, 6, 2, 3, 7, 2, 7, 6, 1, 0, 4, 1, 4, 5, 3, 1, 5, 3, 5, 7, 6, 4, 0, 6, 0, 2];
				for (i = 0; i < indArr.length; i++) {
					indexes[i] = indArr[i];
				}

				h = pi.render.t3d.createMesh(pi.render.t3d.GEO_TYPE_TRIANGLE_LIST, pi.render.t3d.INDEX_TYPE_32BIT, 8, vertices, colors, 36, indexes);
			}

			return pi.res.create(h, undefined, function (handle) {
				pi.render.t3d.destroyMesh(handle);
			});
		},
		createObstacleMesh = function (obstacle, color) {
			var i, n, h, numVer, numInd, vertices, indices, colors,
				polygon = obstacle.polygon,
				height = obstacle.height,
				p1, p2, p3, p4, p5, p6;

			color = color || {r: 255, g: 255, b: 255, a: 255};

			// 计算顶点数和索引数
			numVer = polygon.length * 2;
			numInd = (polygon.length + polygon.length - 2) * 6;

			// 创建顶点、索引、颜色缓冲区
			vertices = pi.lang.createF32Array(numVer * 3);
			colors = pi.lang.createU8Array(numVer * 4);
			indices = pi.lang.createI32Array(numInd);

			// 根据多边形和高度信息填充顶点数据和颜色数据
			for (i = 0; i < polygon.length; i++) {
				vertices[i * 6] = vertices[i * 6 + 3] = polygon[i].x;
				vertices[i * 6 + 2] = vertices[i * 6 + 5] = polygon[i].z;
				vertices[i * 6 + 1] = 0;
				vertices[i * 6 + 4] = height;

				colors[i * 8] = colors[i * 8 + 4] = color.r;
				colors[i * 8 + 1] = colors[i * 8 + 5] = color.g;
				colors[i * 8 + 2] = colors[i * 8 + 6] = color.b;
				colors[i * 8 + 3] = colors[i * 8 + 7] = color.a;
			}

			// 构建侧面索引
			n = 0;
			for (i = 0; i < polygon.length; i++) {
				p1 = (i % polygon.length) * 2;
				p2 = p1 + 1;
				p3 = ((i + 1) % polygon.length) * 2;
				p4 = p3 + 1;

				indices[n++] = p3;
				indices[n++] = p2;
				indices[n++] = p1;
				indices[n++] = p4;
				indices[n++] = p2;
				indices[n++] = p3;
			}

			// 构建底面索引
			for (i = 0; i < polygon.length - 2; i++) {
				p1 = 0;
				p2 = i * 2 + 2;
				p3 = i * 2 + 4;
				p4 = 1;
				p5 = i * 2 + 5;
				p6 = i * 2 + 3;

				indices[n++] = p1;
				indices[n++] = p3;
				indices[n++] = p2;
				indices[n++] = p4;
				indices[n++] = p6;
				indices[n++] = p5;
			}

			h = pi.render.t3d.createMesh(pi.render.t3d.GEO_TYPE_TRIANGLE_LIST,
					pi.render.t3d.INDEX_TYPE_32BIT,
					numVer, vertices, colors, numInd, indices);

			return pi.res.create(h, undefined, function (handle) {
				pi.render.t3d.destroyMesh(handle);
			});
		};

	// 注册所有 vcall 函数句柄
	pi.vcall.makeVCall("s3d.dll", module, vcalls);

	/** 根据指定 mesh-texture-skeleton 创建模型对象 */
	module.createEntity = function (so, cfg) {
		var files = [];

		if (cfg.mesh !== undefined) {
			so.meshFile = cfg.mesh;
			files.push([cfg.mesh, pi.res.MESH]);
		}
		if (cfg.tex !== undefined) {
			so.texFile = cfg.tex;
			files.push([cfg.tex, pi.res.TEX]);
		}
		if (cfg.sk !== undefined) {
			so.skFile = cfg.sk;
			files.push([cfg.sk, pi.res.SKELETON]);
		}

		so.ani = {
			num: 0,
			id0: -1,
			id1: -1,
			weight0: 0,
			weight1: 0,
			time0: 0,
			time1: 1,
			shiftTime: 0,
			numBones: 0
		};

		/** 设置纹理 */
		so.setTex = function (tex) {
			if (so.texFile === tex) {
				return;
			}

			pi.res.loads(tex, pi.res.MESH, function (texData) {
				so.tex = texData;
			});
		};

		/** 将给定物件挂接到本物体的骨头上 */
		so.bind = function (boneID, obj) {
			obj.bindTo = so;
			obj.bindToBone = boneID;
			// 因为本物体可能还没有加载进来，所以先将 c 层的挂接信息清空，等 update 的时候再设置
			vcalls.s3d_set_bind_to(so.sceneHandle, obj.handle, 0, 0);
		};

		/** 直接设置当前动画 */
		so.setAni = function (aniID, reset) {
			reset = reset || false;
			so.ani.num = 1;
			so.ani.id0 = aniID;
			so.ani.id1 = -1;
			so.ani.weight0 = 1;
			so.ani.weight1 = 0;

			if (reset) {
				so.ani.time0 = 0;
				so.ani.time1 = 0;
			}
		};

		/** 过渡到指定动画 */
		so.shiftAni = function (animID, shiftTime) {
			so.ani.num = 2;
			so.ani.id1 = animID;
			so.ani.weight1 = 0;
			so.ani.time1 = 0;
			so.ani.shiftTime = shiftTime;
		};

		/** 获取当前动画 */
		so.getNextAni = function () {
			if (so.ani.num === 1) {
				return so.ani.id0;
			} else {
				return so.ani.id1;
			}
		};

		/** 获取当前所有骨头的变换矩阵 */
		so.getBoneMats = function () {
			return vcalls.s3d_get_bone_mats(so.sceneHandle, so.handle);
		};

		/** 实现节点更新方法 update(更新动画) */
		so.update = function (timeElapsed) {
			so.ani.time0 += timeElapsed;
			so.ani.time1 += timeElapsed;

			// 更新混合权重
			if (so.ani.shiftTime !== 0) {
				if (so.ani.time1 < so.ani.shiftTime) {
					so.ani.weight1 = so.ani.time1 / so.ani.shiftTime;
					so.ani.weight0 = 1 - so.ani.weight1;
				} else {
					so.ani.num = 1;
					so.ani.id0 = so.ani.id1;
					so.ani.id1 = -1;
					so.ani.time0 = so.ani.time1;
					so.ani.time1 = 0;
					so.ani.weight0 = 1;
					so.ani.weight1 = 0;
					so.ani.shiftTime = 0;
				}
			}

			// 更新骨骼动画变换矩阵
			if (so.loaded) {
				// 如果本物体和挂接目标物体都加载了，则设置好 c 层的挂接关系
				if (so.bindTo !== undefined && so.bindTo.loaded) {
					vcalls.s3d_set_bind_to(so.sceneHandle, so.handle, so.bindTo.handle, so.bindToBone);
				}

				if (so.sk !== undefined) {
					vcalls.s3d_update_sk_animation(so.sceneHandle, so.handle, so.sk === undefined ? undefined : so.sk.handle, so.ani.numBones, so.ani.num, so.ani.id0, so.ani.time0, so.ani.weight0, so.ani.id1, so.ani.time1, so.ani.weight1);
				}
			}
		};

		pi.res.loads(files, function (m) {
			var meshData = m[0],
				texData = m[1],
				skData = m[2];

			if (m.error) {
				pi.log("load mesh failed, mesh file = " + cfg.mesh + ", tex file = " + cfg.tex + ", sk file = " + cfg.sk + ", reason = " + m.reason);
			} else {
				so.mesh = meshData;
				so.tex = texData;
				so.sk = skData;
				so.meshID = ++meshID;
				so.translucent = false;
				so.attach(meshData);
				if (skData !== undefined) {
					so.ani.numBones = vcalls.s3d_get_sk_bonenum(skData.handle);
				}
				so.loaded = true;
			}
		});
	};

	/** 创建障碍体 */
	module.createObstacleEntity = function (so, obstacle, color) {
		var model = createObstacleMesh(obstacle, color);
		so.attach(model);
		so.ro = model;
		so.loaded = true;
	};

	/** 创建矩形线框
		color: 线框颜色 {r, g, b, a}
	 */
	module.createCube = function (so, onlyFrame, color) {
		var model = createCube(onlyFrame, color);
		so.attach(model);
		so.ro = model;
		so.loaded = true;
	};

	/**创建扇形对象*/
	module.createSector = function (so, radius, radian, color, num) {
		var model = createSector(radius, radian, color, num);
		so.attach(model);
		so.ro = model;
		so.loaded = true;
	};

	/**创建圆锥对象*/
	module.createCone = function (so, radius, height, color, num) {
		var model = createCone(radius, height, color, num);
		so.attach(model);
		so.ro = model;
		so.loaded = true;
	};

	/**创建圆柱对象*/
	module.createCylinder = function (so, radius, height, color, num) {
		var model = createCylinder(radius, height, color, num);
		so.attach(model);
		so.ro = model;
		so.loaded = true;
	};


	/** 创建线对象 */
	module.createLine = function (so, startPt, endPt, color) {
		var model = createLines([{start: startPt, end: endPt, color: color}]);
		so.attach(model);
		so.ro = model;
		so.loaded = true;
	};

	/** 创建线段列表对象 */
	module.createLines = function (so, lines) {
		var model = createLines(lines);
		so.attach(model);
		so.ro = model;
		so.loaded = true;
	};

	return module;
});
